package com.maoye.ossp.bpm.bpmweb.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.hotent.base.core.util.FileUtil;
import com.hotent.base.core.util.string.StringUtil;
import com.maoye.ossp.bpm.bpmweb.controller.executor.StartProcessExecutor;
import com.maoye.ossp.bpm.bpmweb.controller.executor.TaskFinishExecutor;
import com.maoye.ossp.bpm.bpmweb.utils.DataHolder;
import com.maoye.ossp.bpm.bpmweb.utils.NestedFormUtil;
import com.maoye.ossp.bpmagent.context.BpmAgentConfiguration;
import com.maoye.ossp.bpmagent.engine.IProcessInstanceEngine;
import com.maoye.ossp.bpmagent.model.TaskOpinion;
import com.maoye.ossp.sys.org.util.UserUtils;

@Controller
@RequestMapping("bpm/agent/process/")
public class Bpm4OsspController {
	private Logger logger = Logger.getLogger(Bpm4OsspController.class);

	@Resource(name = "bpmAgentConfiguration")
	private BpmAgentConfiguration bpmAgentConfiguration;

	private Pattern httpRegex = Pattern.compile("^http.*",
			Pattern.CASE_INSENSITIVE);

	/**
	 * 表单一路径(测试用)
	 * 
	 * @param redirectAttributes
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 * @deprecated
	 */
	@RequestMapping(value = "/form/test")
	public String test(RedirectAttributes redirectAttributes,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		String taskId = request.getParameter("taskId");
		if (taskId != null && taskId.trim().length() > 0) {
			Map<String, Object> vars = bpmAgentConfiguration
					.getBpmAgentContext().getTaskEngine("taskEngineImpl")
					.getVariableByTaskId(taskId);
			model.addAttribute("vars", vars);
		}
		return "/bpm/agent/form/test";
	}

	/**
	 * 表单二路径(测试用)
	 * 
	 * @param redirectAttributes
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 * @deprecated
	 */
	@RequestMapping(value = "/form/test2")
	public String test2(RedirectAttributes redirectAttributes,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		String taskId = request.getParameter("taskId");
		if (taskId != null && taskId.trim().length() > 0) {
			Map<String, Object> vars = bpmAgentConfiguration
					.getBpmAgentContext().getTaskEngine("taskEngineImpl")
					.getVariableByTaskId(taskId);
			model.addAttribute("vars", vars);
		}
		return "/bpm/agent/form/test2";
	}

	@RequestMapping(value = "processDefinition")
	public String processDefinition(HttpServletRequest request, Model model) {
		return "/bpm/bpmsap/def/processDefinition";
	}

	/**
	 * 表单数据收集方法(测试用)
	 * 
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 * @deprecated
	 */
	@RequestMapping(value = "testSubmit")
	@SuppressWarnings("unchecked")
	public void testSubmit(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		logger.info("表单提交...");
		// 1. 获取缓存对象
		DataHolder holder = NestedFormUtil.getDataHolder(request);
		// 2. 处理表单数据
		Map<String, Object> map = request.getParameterMap();
		// String token = "";
		Map<String, Object> data = new HashMap<String, Object>();
		Set<String> set = map.keySet();
		// 获取流程变量对象
		Map<String, Object> vars = (Map<String, Object>) holder
				.getData(DataHolder.KEY_VARS);
		for (String name : set) {
			if ("token".equals(name)) {
				// token = request.getParameter(name.toString());
				continue;
			}
			data.put(name, request.getParameter(name.toString()));
			// 添加流程变量-参考
			vars.put(name, request.getParameter(name.toString()));
		}

		try {
			// 参考
			// 保存表单数据操作:save(data);

			// 4. 设置表单数据到缓存对象，设值数据根据业务，主要目的是标记表单处理完成
			// 设置表单数据，内置流程数据检查执行功能，返回null（执行条件不足）或执行结果
			String result = holder.setData(DataHolder.KEY_FORM, data);
			if (result != null) {// 如果有返回值
				// 5. 清空缓存
				NestedFormUtil.clear(request.getSession());
				request.setAttribute("message", "{code:\"1001\"}");
				// 6.处理信息通知到前台
				sendMsgToPage(request, response);
			}
		} catch (Exception e) {
			// 7. 标记执行中发生异常
			holder.markError();
			// 8. 异常信息通知到前台
			request.setAttribute(
					"message",
					String.format("{\"code\":\"1002\",\"msg\":\"%s\"}",
							e.getMessage()));
			sendMsgToPage(request, response);
		}
	}

	/**
	 * 重定向到信息接收页面
	 * 
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	private void sendMsgToPage(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		request.getRequestDispatcher("/bpm/agent/process/toMessagePage")
				.forward(request, response);
	}

	/**
	 * 流程处理信息接收页面
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "toMessagePage")
	public String toMessagePage(HttpServletRequest request,
			HttpServletResponse response) {
		return "/bpm/agent/message";
	}

	/**
	 * 流程启动处理方法
	 * 
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "startProcess")
	public void startProcess(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		logger.info("流程启动...");
		JSONObject baseInfo = new JSONObject();
		DataHolder holder = NestedFormUtil.getDataHolder(request);
		if (holder.hasError()) {// 表单提交发生异常取消后续动作
			holder.clear();
			NestedFormUtil.clear(request.getSession());
			return;
		}
		// String token = request.getParameter("token");

		baseInfo.element("status", request.getParameter("flowStatus"));
		baseInfo.element("flowKey", request.getParameter("flowKey"));
		baseInfo.element("procDefId", request.getParameter("defId"));
		// 设置流程启动执行对象
		holder.setExcutor(new StartProcessExecutor(bpmAgentConfiguration
				.getBpmAgentContext().getProcessInstanceEngine(
						"processInstanceEngineImpl")));
		holder.setParameter("userKey", getUserKey(request));
		// 设置程数数据，内置表单数据检查执行功能，返回null（执行条件不足）或执行结果
		String result = holder
				.setData(DataHolder.KEY_NODE, baseInfo.toString());
		if (result != null) {
			NestedFormUtil.clear(request.getSession());
			request.setAttribute("message", "{code:\"1001\"}");
			sendMsgToPage(request, response);
		}
	}

	@RequestMapping(value = "download")
	public void download(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		InputStream is = bpmAgentConfiguration.getBpmAgentContext()
				.getProcessInstanceEngine("processInstanceEngineImpl")
				.loadProperties();
		byte[] bs = new byte[1024 * 2];
		ServletOutputStream out = response.getOutputStream();
		while (is.read(bs) != -1) {
			out.write(bs);
		}
		out.close();
	}

	/**
	 * 任务完成处理方法
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "finishTask")
	public void finishTask(HttpServletRequest request,
			HttpServletResponse response, Model model) throws ServletException,
			IOException {
		logger.info("完成任务...");
		DataHolder holder = NestedFormUtil.getDataHolder(request);
		if (holder.hasError()) {// 表单提交发生异常取消后续动作
			holder.clear();
			NestedFormUtil.clear(request.getSession());
			return;
		}
		// String token = request.getParameter("token");

		// 流程数据收集
		JSONObject baseInfo = new JSONObject();
		String taskId = request.getParameter("taskId");
		String instId = request.getParameter("instanceId");
		String action = request.getParameter("actionName");
		baseInfo.element("taskId", taskId);
		baseInfo.element("instId", instId);
		// AGREE("agree"),BACK("back"),END("end");
		baseInfo.element("actionName", action);

		if ("backToStart".equals(action)) {// 驳回可以不提交表单
			holder.remove(DataHolder.KEY_FORM);
		}

		// 设置流程任务完成执行对象
		holder.setExcutor(new TaskFinishExecutor(bpmAgentConfiguration
				.getBpmAgentContext().getTaskEngine("taskEngineImpl")));
		holder.setParameter("userKey", getUserKey(request));
		// 设置程数数据，内置表单数据检查执行功能，返回null（执行条件不足）或执行结果
		String result = holder
				.setData(DataHolder.KEY_NODE, baseInfo.toString());
		if (result != null) {
			NestedFormUtil.clear(request.getSession());
			request.setAttribute("message", "{code:\"1001\"}");
			sendMsgToPage(request, response);
		}
	}

	/**
	 * 设置任务执行人
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "assign")
	public void assign(HttpServletRequest request,
			HttpServletResponse response, Model model) throws ServletException,
			IOException {
		String taskId = request.getParameter("taskId");
		String assigneeId = request.getParameter("assigneeId");
		String msg = bpmAgentConfiguration.getBpmAgentContext()
				.getTaskEngine("taskEngineImpl")
				.assigTask(taskId, assigneeId, getUserKey(request));
	}
	
	/**
	 * 添加候选人信息
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "addCandidate")
	public void addCandidate(HttpServletRequest request,
			HttpServletResponse response, Model model) throws ServletException,
			IOException {
		String taskId = request.getParameter("taskId");
		String[] userIds = request.getParameterValues("userIds");
		String msg = bpmAgentConfiguration.getBpmAgentContext()
				.getTaskEngine("taskEngineImpl")
				.addCandidateUsers(taskId, userIds, getUserKey(request));
	}

	/**
	 * 挂起
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws ServletException
	 * @throws IOException
	 */
	public void suspendTask(HttpServletRequest request,
			HttpServletResponse response, Model model) throws ServletException,
			IOException {

	}

	/**
	 * 挂起
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "bpmImage")
	public void bpmImage(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0L);
		
		String bpmnDefId = request.getParameter("bpmnDefId");
		String instanceId = request.getParameter("instanceId");
		InputStream is = null;
		IProcessInstanceEngine engine = bpmAgentConfiguration
				.getBpmAgentContext().getProcessInstanceEngine(
						"processInstanceEngineImpl");
		if (StringUtil.isNotEmpty(bpmnDefId)) {
			if (StringUtil.isNotEmpty(instanceId)) {
				Map<String, String> status = engine
						.getProcessInstanceStatus(instanceId);
				is = engine.getDiagramByBpmnDefIdAndColor(bpmnDefId, status);
			} else {
				is = engine.getDiagramByBpmnDefId(bpmnDefId);
			}
		}
		if (is != null) {
			response.setContentType("image/png");
			OutputStream out = new BufferedOutputStream(response.getOutputStream());
			try {
				byte b[] = new byte[1024];
				int len = is.read(b);
				while (len > 0) {
					out.write(b, 0, len);
					len = is.read(b);
				}
			} finally {
				is.close();
				out.close();
			}
		}
	}

	private String getUserKey(HttpServletRequest request) {
//		return "1";
		return "" + UserUtils.getUser().getId();
	}

	/**
	 * 跳转到流程启动页面
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "toStartProcess")
	public String toStartProcess(HttpServletRequest request,
			HttpServletResponse response, Model model) {
		String flowKey = request.getParameter("flowKey");

		String json = bpmAgentConfiguration.getBpmAgentContext()
				.getNodeDefEngine("nodeDefEngineImpl")
				.getNodeDefByProcessDefAndKey(flowKey, null);
		if (json != null) {
			JSONObject jo = JSONObject.fromObject(json);
			model.addAttribute("node", jo);
			bindingFormUrL(request, model, jo, null);
			
		}

		model.addAttribute("flowKey", flowKey);
		return "/bpm/agent/osspstart/startIndex";
	}

	/**
	 * 跳转到任务处理页面
	 * 
	 * @param taskId
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "toProcessTask/{taskId}")
	public String toProcessTask(@PathVariable(value = "taskId") String taskId,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		String json = bpmAgentConfiguration.getBpmAgentContext()
				.getTaskEngine("taskEngineImpl").getTaskById(taskId);
		if (json != null) {
			JSONObject task = JSONObject.fromObject(json);
			JSONObject nodeDef = (JSONObject) task.get("nodeDef");
			Map<String, Object> args = new HashMap<String, Object>();
			args.put("taskId", taskId);
			args.put("defId", task.getString("proDefId"));
			// 设置到nodeDef
			nodeDef.element("proDefId", task.getString("proDefId"));
			bindingFormUrL(request, model, nodeDef, args);
			model.addAttribute("task", (Map<String, Object>) task);

			
			List<TaskOpinion> list = bpmAgentConfiguration
					.getBpmAgentContext()
					.getProcessInstanceEngine("processInstanceEngineImpl")
					.getTaskOpinionByProInsId(
							String.valueOf(task.get("instanceId")),
							getUserKey(request));
			model.addAttribute("list", list);
		}
		return "/bpm/agent/osspprocess/taskProcess";
	}

	/**
	 * 添加请求参数
	 * 
	 * @param request
	 * @param model
	 * @param nodeDef
	 * @param args
	 */
	private void bindingFormUrL(HttpServletRequest request, Model model,
			JSONObject jo, Map<String, Object> args) {
		String url = jo.getString("formValue");
		if (url != null) {
			if (args != null) {
				if (url.indexOf("?") == -1) {
					url += "?";
				} else {
					url += "&";
				}
				url += toString(args);
			}
			if (httpRegex.matcher(url).matches()) {
				model.addAttribute("formURL", url);
			} else {
				model.addAttribute("formURL", request.getContextPath() + "/"
						+ url);
			}
		}
		JSONArray outNodeList = jo.getJSONArray("outNodeList");
		if (outNodeList != null && outNodeList.size() > 0) {
			StringBuilder sb = new StringBuilder();
			for (Object obj : outNodeList) {
				if (sb.length() > 0) {
					sb.append(",");
				}
				sb.append(((JSONObject) obj).getString("nodeName"));
			}
			model.addAttribute("outNodeList", sb.toString());
		}
		model.addAttribute("defId", jo.getString("proDefId"));
	}

	/**
	 * Map to string
	 * 
	 * @param args
	 * @return
	 */
	private String toString(Map<String, Object> args) {
		StringBuilder sb = new StringBuilder();
		for (Map.Entry<String, Object> e : args.entrySet()) {
			if (sb.length() > 0) {
				sb.append("&");
			}
			sb.append(e.getKey()).append("=").append(e.getValue());
		}
		return sb.toString();
	}
}
